package fi.solita.dojo.mazeserver.game

import swing._
import ui._
import internal._
import map._
import client._
import java.awt.{Color}
import scala.collection._


case class PlayerList(players: List[Player]) {

	def playerIndex(name: String) = names.indexOf(name)

	def size(): Int = players.size

	def names(): List[String] = players map (_.name) toList

	def getPlayer(name: String) = players find (_.name == name)

	def getPlayerNN(name: String) = getPlayer(name) match {
	case Some(p) => p
	case None => throw new IllegalStateException("Unknown player")
	}

	def replace(player: Player): PlayerList = PlayerList(players map ((p: Player) => if (player.equals(p)) player else p))

	def replaceMany(plrs: List[Player]): PlayerList =
		plrs.foldLeft(this)((newPl,p) => newPl.replace(p))

		def reservedName(name: String) = getPlayer(name) != None    

		def playerConnected(p: Player) = ClientService.clientNameInUse(p.name)

		def execute(p: Player): PlayerList = {
		p.nextAction match {
		case Some(action) => execute(p, action)
		case None => this
		}  
	}

	def execute(p: Player, a: GameAction): PlayerList = {
		a match {
		case Move1() => move1(p.name)
		case Move2() => move1(p.name).move1(p.name)
		case Move3() => move1(p.name).move1(p.name).move1(p.name)
		case MoveBack() => moveBack(p.name)
		case TurnRight() => replaceMany(p.turn(Turn.Right) :: Nil)
		case TurnLeft() => replaceMany(p.turn(Turn.Left) :: Nil)
		case DoNothing() => collectAndMoveToHead(p)
		case _ => this
		}
	}

	def move1(name: String): PlayerList = {
		val p = getPlayerNN(name)
		val pl = if (p.freeToMove) move(p, p.heading)._1 else Nil
		replaceMany(pl)
	}

	def moveBack(name: String): PlayerList = {
		val p = getPlayerNN(name)
		val pl = if (p.freeToMove) move(p, Directions.opposite(p.heading))._1 else Nil
		replaceMany(pl)
	}

	def collectAndMoveToHead(p:Player): PlayerList = 
		PlayerList(GameWorld.collectPoint(p) :: (players filter (_.name != p.name)))

	def move(p: Player, d: Directions.Direction): (List[Player], Boolean) = {
		val (movedPlayers, success) = playerAt(p.coordinates.neighbour(d)) match {
		case Some(player) => move(player, d)
		case None => (Nil, p.gameLocation.passable(d))
		}

		if (success) (p.move(d) :: movedPlayers, true) else (Nil, false)
	}

	def playerAt(c: Coordinates): Option[Player] = players find (_.coordinates == c)

	def allPlayersHaveActions(): Boolean = players.forall((p: Player) => (p.nextAction != None || !playerConnected(p))) 

	def moveToTop(p: Player): PlayerList = PlayerList(p :: removePlayer(p.name).players)

	private[game] def removePlayer(name: String): PlayerList = {
		PlayerList(players filter(_.name != name))
	}

	def addPlayer(name: String): PlayerList = {
		val player = Player(name, 
				GameWorld.initialLocation, 
				Directions.randomDirection, PlayerColors.nextColor, 0, None)
				PlayerList( player :: players)
	}

	def reset(): PlayerList = PlayerList(players map (_.reset))
}

object PlayerColors {

	var i = 0

	def nextColor() = {
		val color = colors(i)
		i = (i + 1) % colors.size
		color
	}

	val colors = List((Color.RED, "red"), 
			(Color.BLUE, "blue"),
			(Color.GREEN, "green"), 
			(Color.ORANGE, "orange"), 
			(Color.PINK, "pink"),
			(Color.YELLOW, "yellow"),
			(Color.CYAN, "cyan"),
			(Color.MAGENTA, "magenta"),
			(Color.GRAY, "gray"),
			(Color.DARK_GRAY, "dark gray"),
			(Color.LIGHT_GRAY, "light gray"))   
}


